package string.leetcode.medium;

/**
 * @author bruin_du
 * @description 表示数值的字符串
 * @date 2022/6/14 23:12
 **/
public class Offer20_IsNumber {
    int index = 0;
    public boolean isNumber(String s) {
        s = s.trim();
        int len = s.length();
        char[] arr = s.toCharArray();
        //flag保存最开始是否是整数
        boolean flag = number(arr);
        //字符串遵循A.[[B](e|E)C],.B[(e|E)C]两种模式
        //A和C为可带符号的整数,B只能是不带符号的整数
        //因为如果有小数和指数,则必有先后顺序,所以向后用if判断进行不同操作即可
        //有'.',进行无符号整数判断
        if(index < arr.length && arr[index] == '.') {
            index++;
            //更新flag的值,用||的原因
            //1.小数点前可以没有整数,如.123等于0,123
            //2.小数点后可没有数字,如233.
            //3.小数点前后都可以有数字
            flag = isUnsignedNumber(arr) || flag;
        }
        //如果出现字符e|E,进行指数部分的判断
        if(index < arr.length && (arr[index] == 'E' || arr[index] == 'e')) {
            index++;
            //更新flag的值,用&&的原因
            //1.当e|E前面没有数字时,不能表示数字,如e1
            //2.当e|E后面没有整数时,不能表示数字,如12e,12e+5.4
            flag = flag && number(arr);
        }
        //如果前面的规则都满足,则flag为true,并且要走完字符串时
        //最终结果才是合法的
        return flag && index == arr.length;
    }

    private boolean number(char[] arr) {
        if(index < arr.length && (arr[index] == '-' || arr[index] == '+')) {
            index++;
        }
        return isUnsignedNumber(arr);
    }

    private boolean isUnsignedNumber(char[] arr) {
        int place = index;
        while(index < arr.length && Character.isDigit(arr[index])) {
            index++;
        }
        //当arr中有数字时,就返回true
        return index > place;
    }
}
